package mysql

import (
	db_utils "gitee.com/zy_blue7/db-convert/db-utils"
	"strconv"
	"time"
)

type MysqlType string

const (
	BIT                MysqlType = "BIT"
	BLOB               MysqlType = "BLOB"
	DATE               MysqlType = "DATE"
	TEXT               MysqlType = "TEXT"
	TINYTEXT           MysqlType = "TINYTEXT"
	MEDIUMTEXT         MysqlType = "MEDIUMTEXT"
	LONGTEXT           MysqlType = "LONGTEXT"
	DATETIME           MysqlType = "DATETIME"
	DECIMAL            MysqlType = "DECIMAL"
	DOUBLE             MysqlType = "DOUBLE"
	ENUM               MysqlType = "ENUM"
	FLOAT              MysqlType = "FLOAT"
	GEOMETRY           MysqlType = "GEOMETRY"
	MEDIUMINT          MysqlType = "MEDIUMINT"
	UNSIGNED_MEDIUMINT MysqlType = "UNSIGNED MEDIUMINT"
	JSON               MysqlType = "JSON"
	UNSIGNED_INT       MysqlType = "UNSIGNED INT"
	INT                MysqlType = "INT"
	LONGBLOB           MysqlType = "LONGBLOB"
	BIGINT             MysqlType = "BIGINT"
	UNSIGNED_BIGINT    MysqlType = "UNSIGNED BIGINT"
	MEDIUMBLOB         MysqlType = "MEDIUMBLOB"
	NULL               MysqlType = "NULL"
	SET                MysqlType = "SET"
	BINARY             MysqlType = "BINARY"
	SMALLINT           MysqlType = "SMALLINT"
	UNSIGNED_SMALLINT  MysqlType = "UNSIGNED SMALLINT"
	CHAR               MysqlType = "CHAR"
	TIME               MysqlType = "TIME"
	TIMESTAMP          MysqlType = "TIMESTAMP"
	TINYINT            MysqlType = "TINYINT"
	UNSIGNED_TINYINT   MysqlType = "UNSIGNED TINYINT"
	TINYBLOB           MysqlType = "TINYBLOB"
	VARCHAR            MysqlType = "VARCHAR"
	VARBINARY          MysqlType = "VARBINARY"
	YEAR               MysqlType = "YEAR"
	VECTOR             MysqlType = "VECTOR"
)

// 使用类型断言或赋值来让编译器检查 MysqlConvertValue结构体是否实现某接口
var _ db_utils.ConvertValue = (*MysqlConvertValue)(nil)

// 开发阶段：使用编译时检查 (var _ Interface = (*Type)(nil))

type MysqlConvertValue struct{}

// 转换值为适合数据库的类型
// /Users/blue7/go/pkg/mod/github.com/go-sql-driver/mysql@v1.9.2/fields.go
// todo 每个连接对象都有一个这样的实现，里面列出了所有的mysql的数据类型
/**

func (mf *mysqlField) typeDatabaseName() string {
	switch mf.fieldType {
	case fieldTypeBit:
		return "BIT"
	case fieldTypeBLOB:
		if mf.charSet != binaryCollationID {
			return "TEXT"
		}
		return "BLOB"
	case fieldTypeDate:
		return "DATE"
	case fieldTypeDateTime:
		return "DATETIME"
	case fieldTypeDecimal:
		return "DECIMAL"
	case fieldTypeDouble:
		return "DOUBLE"
	case fieldTypeEnum:
		return "ENUM"
	case fieldTypeFloat:
		return "FLOAT"
	case fieldTypeGeometry:
		return "GEOMETRY"
	case fieldTypeInt24:
		if mf.flags&flagUnsigned != 0 {
			return "UNSIGNED MEDIUMINT"
		}
		return "MEDIUMINT"
	case fieldTypeJSON:
		return "JSON"
	case fieldTypeLong:
		if mf.flags&flagUnsigned != 0 {
			return "UNSIGNED INT"
		}
		return "INT"
	case fieldTypeLongBLOB:
		if mf.charSet != binaryCollationID {
			return "LONGTEXT"
		}
		return "LONGBLOB"
	case fieldTypeLongLong:
		if mf.flags&flagUnsigned != 0 {
			return "UNSIGNED BIGINT"
		}
		return "BIGINT"
	case fieldTypeMediumBLOB:
		if mf.charSet != binaryCollationID {
			return "MEDIUMTEXT"
		}
		return "MEDIUMBLOB"
	case fieldTypeNewDate:
		return "DATE"
	case fieldTypeNewDecimal:
		return "DECIMAL"
	case fieldTypeNULL:
		return "NULL"
	case fieldTypeSet:
		return "SET"
	case fieldTypeShort:
		if mf.flags&flagUnsigned != 0 {
			return "UNSIGNED SMALLINT"
		}
		return "SMALLINT"
	case fieldTypeString:
		if mf.flags&flagEnum != 0 {
			return "ENUM"
		} else if mf.flags&flagSet != 0 {
			return "SET"
		}
		if mf.charSet == binaryCollationID {
			return "BINARY"
		}
		return "CHAR"
	case fieldTypeTime:
		return "TIME"
	case fieldTypeTimestamp:
		return "TIMESTAMP"
	case fieldTypeTiny:
		if mf.flags&flagUnsigned != 0 {
			return "UNSIGNED TINYINT"
		}
		return "TINYINT"
	case fieldTypeTinyBLOB:
		if mf.charSet != binaryCollationID {
			return "TINYTEXT"
		}
		return "TINYBLOB"
	case fieldTypeVarChar:
		if mf.charSet == binaryCollationID {
			return "VARBINARY"
		}
		return "VARCHAR"
	case fieldTypeVarString:
		if mf.charSet == binaryCollationID {
			return "VARBINARY"
		}
		return "VARCHAR"
	case fieldTypeYear:
		return "YEAR"
	case fieldTypeVector:
		return "VECTOR"
	default:
		return ""
	}
}

*/
// 如果val 是 []unit8 表示的是字节数据，需要自己解析为需要的类型
func (mcv *MysqlConvertValue) ConvertValue(val interface{}, colTypeName string) interface{} {
	if val == nil {
		return nil
	}

	// colType *sql.ColumnType , colType.DatabaseTypeName()
	switch MysqlType(colTypeName) {
	case INT, BIGINT, TINYINT, SMALLINT, MEDIUMINT:
		switch v := val.(type) {
		case int64:
			return v
		case []uint8: // 处理MySQL返回的[]byte
			str := string(v)
			if i, err := strconv.ParseInt(str, 10, 64); err == nil {
				return i
			}
		}
	case VARCHAR, TEXT, CHAR, TINYTEXT, MEDIUMTEXT, LONGTEXT:
		switch v := val.(type) {
		case string:
			return v
		case []uint8:
			return string(v)
		}
	case DATETIME, TIMESTAMP:
		switch v := val.(type) {
		case time.Time:
			return v
		case []uint8:
			if t, err := time.Parse("2006-01-02 15:04:05", string(v)); err == nil {
				return t
			}
		}
	case FLOAT, DOUBLE:
		switch v := val.(type) {
		case float32, float64:
			return v
		}
	}

	return val
}
